/*
 *Copyright (c) 2024 Black Sesame Technologies
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
*/

#ifndef __HSCG_FIRMWARE_STATISTIC_H__
#define __HSCG_FIRMWARE_STATISTIC_H__
#include "../../library/types.h"
#include "hscg_firmware.h"              //统计信息
#include "hscg_firmware_code_statistic.h"
#include "hscg_firmware_packet_statistic.h"

/****************************  统计信息相关功能函数 START *****************************/
struct port_stats {
    uint32 rx_n;
    uint32 rx_drop_n;
    uint32 tx_n;
    uint32 tx_err_n;
};

#define CAN_STATS_PORT_NUM 16

// 统计信息，保存在RAM中，可以通过A核的工具获取并解析
struct STATISTICS {
    uint32 magic_word;                // 统计信息标识
    uint32 op_code;                   // 外部交互操作码

    /* each port stats */
    struct port_stats can[CAN_STATS_PORT_NUM];        // CAN各PORT收发包统计
    struct port_stats eth;            // 与ETH核的交互统计

    uint64 eth_2_can_enqueue_count;    //往ETH_2_CAN队列中加入的元素数量
    uint64 eth_2_can_dequeue_count;    //从ETH_2_CAN队列中出队的数量
    uint64 eth_2_can_read_ptr;         //ETH_2_CAN队列 read指针
    uint64 eth_2_can_write_ptr;        //ETH_2_CAN队列 write指针
    uint64 eth_2_can_drop_packet;      //ETH_2_CAN方向由于各种原因丢包的数量，TODO细化各个原因

    uint64 can_2_enqueue_count;        //CAN_2_ETH队列中入队数量
    uint64 can_2_dequeue_count;        //CAN_2_ETH队列中出队数量
    uint64 can_2_read_ptr;             //CAN_2_ETH队列 read指针
    uint64 can_2_write_ptr;            //CAN_2_ETH队列 write指针
    uint64 can_2_eth_drop_packet;      //CAN_2_ETH方向由于各种原因丢包数量，TODO细化各个原因

    uint64 msgbox_recv_packet;         //msgbox收到的消息数量
    uint64 msgbox_send_packet;         //msgbox发送的消息数量

    /* timestamp */
    uint64 timestamp_startup;

    /* for perf */
#ifdef STATISTICS_CODE_TIMESTAMP_ENABLE
    uint64 runtime_total;
    uint32 code_timestamp_loop;
    uint32 code_timestamp_step;
#endif
#ifdef STATISTICS_PACKET_TIMESTAMP_ENABLE
    uint32 packet_timestamp_loop;
    uint32 packet_timestamp_step;
#endif
#if defined(STATISTICS_CODE_TIMESTAMP_ENABLE) && defined (STATISTICS_PACKET_TIMESTAMP_ENABLE)
#elif defined(STATISTICS_CODE_TIMESTAMP_ENABLE)
    uint64 rsvd_ts[1];
#elif defined(STATISTICS_PACKET_TIMESTAMP_ENABLE)
    uint64 rsvd_ts[2];
#else
    uint64 rsvd_ts[3];                   //保留
#endif
    /* end for perf */

    uint32 rsvd[26];                   //保留
}; //total 512B

extern struct STATISTICS *statistics;
#define STATISTICS_UPDATE(key, value) \
    do {                              \
        statistics->key = value;       \
    } while(0)

#define STATISTICS_INC(_point, _key)    \
    do {                                \
        ++statistics->_point._key;      \
    } while(0)


#define STATS_INC_ETH_RX()      STATISTICS_INC(eth, rx_n)
#define STATS_INC_ETH_RX_DROP() STATISTICS_INC(eth, rx_drop_n)
#define STATS_INC_ETH_TX()      STATISTICS_INC(eth, tx_n)
#define STATS_INC_ETH_TX_ERR()  STATISTICS_INC(eth, tx_err_n)

#define STATS_INC_CAN_RX(_port)      STATISTICS_INC(can[_port], rx_n)
#define STATS_INC_CAN_RX_DROP(_port) STATISTICS_INC(can[_port], rx_drop_n)
#define STATS_INC_CAN_TX(_port)      STATISTICS_INC(can[_port], tx_n)
#define STATS_INC_CAN_TX_ERR(_port)  STATISTICS_INC(can[_port], tx_err_n)

#define STATS_MAGIC_WORD 0x43414E53 // 'C' 'A' 'N' 'S'
#define STATS_OP_KEY 0xA5
#define STATS_KEY_OFFSET 24
#define STATS_KEY_MASK 0xFF

#define STATS_CMD_MASK 0xFF
#define STATS_CMD_OFFSET 16

#define STATS_CMD_CLEAN_ALL 0x1
#define STATS_CMD_CLEAN_CAN 0x2
#define STATS_CMD_CLEAN_ETH 0x3


#define STATS_PARA_MASK 0xFFFF
#define STATS_PARA_OFFSET 0

uint64 util_get_GTC_time64();
void init_statistics();
void get_statistics(const uint64 context, const ext_info_t *info);
void staticstics_run(void);

#endif /* __HSCG_FIRMWARE_STATISTIC_H__ */